<template>
<!--    游戏菜单-->
    <div>
        <SnakeMenu :show="obj.showMenu" @sure="updateGameSetting" @cancel="cancelGameSetting">

        </SnakeMenu>
    </div>

<!--    游戏开始-->
    <div class="snake-box flex-center-col">

        <div class="snake-game-title">
            <div class="flex-center-col">
                <span style="font-size: 35px;margin-bottom: 50px">
                    {{gameSetting.play?'开始':'暂停'}}
                </span>
                <div>

                    得分:
                    <span>
                    {{gameSetting.score}}
                </span>
                    分
                </div>

                <div>
                    速度:
                    <span>
                {{gameSetting.speed}}
                </span>
                    迈
                </div>

                <div>
                    当前游戏难度:
                    <span>
                    {{getGameLevel}}
                </span>
                </div>

                <!--        游戏操作指南-->
                <div class="game-manual-box">

                    游戏操作指南
                    <div v-for="(manual,y) in gameSetting.manual" v-html="manual.content" class="game-manual">

                    </div>
                </div>
            </div>
        </div>



        <div class="snake-map"  >
            <div v-for="(itemRow,index) in map.value"

            >

                <span v-for="(itemCol,j) in itemRow"
                     :class="getColor(itemCol)"
                     :style="{width:map.mapSetting.itemWidth+'px',height:map.mapSetting.itemWidth+'px'}">

                </span>
            </div>

        </div>



    </div>
</template>

<script>
    import {computed, reactive} from "@vue/reactivity";
    import {onMounted,watch} from "@vue/runtime-core";
    import {errorMessage, goTo, goTop, successMessage} from "@/assets/js/utils";
    import SnakeMenu from "@/components/life/SnakeMenu";

    export default {
        name: "RetroSnaker",
        components: {SnakeMenu},
        setup(){

            let obj=reactive({
                showMenu:false,
                timer:{}, // 最后一次移动（定时器  setTimeout()）
                backCount:0
            })
            let gameSetting=reactive({
                play:false,
                speedTime:10,//移动倍数
                baseSpeed:100,
                speed:100 ,
                score:0 ,
                defaultMoveDirection:2, // 1 左 / 2 上 / 3 右 / 4 下
                level:1 ,//难度模式: 1 ，2 ，3 ，4 ，5
                manual:[
                    {
                        content:"方向键: ← ↑ → ↓  或者 a w d s ",

                    },
                    {
                       content:'加速: 【长按】方向键'
                    },
                    {
                       content:'暂停: 空格键 / space'
                    },
                    {
                        content:'菜单栏:   Esc'
                    }
                ]           //操作指南
            })
            let map=reactive({
                mapSetting:{
                    row:20,
                    col:30,
                    itemWidth:20,

                },
                value:[

                ]
            })

            let snake=reactive({
                x:0,
                y:0,
                len:1,
                body:[],
                lastX:0,
                lastY:0,
                moveDirection:gameSetting.defaultMoveDirection
            })


            // 开始游戏，启动定时任务
            let startGame=()=>{
                if(gameSetting.play) {
                    obj.timer=setTimeout(() => {
                        switch (snake.moveDirection) {
                            case 1:
                                moveLeft();
                                break;
                            case 2:
                                moveUp();
                                break
                            case 3:
                                moveRight();
                                break
                            case 4:
                                moveDown();
                                break;
                        }

                        startGame()


                    }, getSpeed())
                }
            }

            // 游戏菜单开关
            let menuToggle=()=>{

                obj.showMenu=!obj.showMenu
                pauseGame()


            }

            let cancelGameSetting=(setting)=>{
                menuToggle()
            }
            // 修改游戏设置
            let updateGameSetting= (setting) => {
                // 修改游戏设置
                gameSetting.level = setting.level
                // 重新初始化游戏
                initGame()
                // 开始游戏
                startGame()
            }
            let pauseGame=()=>{
                // 暂停游戏
                if(gameSetting.play){
                    clearTimeout(obj.timer)
                    gameSetting.play=false
                }else{
                    // 开始游戏
                    gameSetting.play=true
                    startGame()
                }
            }
            // 显示游戏难度
            let getGameLevel=computed(()=>{
                switch (gameSetting.level) {
                    case 1: return '简单'
                    case 2: return '初级'
                    case 3: return '中级'
                    case 4: return '高级'
                    case 5: return '地狱'
                }
            })
            // 检查是否允许移动
            let check=()=>{

                // 是否撞墙
                if(snake.x < 0 || snake.x >map.mapSetting.row-1 ){
                    return false;
                }
                // 是否撞墙
                if(snake.y < 0 || snake.y >map.mapSetting.col-1){
                    return false;
                }
                // 是否撞蛇身
                if( map.value[snake.x][snake.y] === 2 ){
                    return false;
                }

                return true
            }

            // 加入蛇身,参数: x,y
            let appendSnakeBody=(x,y)=>{
                snake.body.push({
                    x:x,
                    y:y
                })
                snake.len=snake.body.length
            }


            // 返回移动间隔时间，单位ms，用于startGame函数
            let getSpeed=()=>{
                return 1000 - gameSetting.speed
            }

            // 用于吃到食物后修改蛇的移动速度
            let updateSpeed=()=>{
                gameSetting.speed=gameSetting.baseSpeed+gameSetting.level*gameSetting.speedTime*gameSetting.score

            }
            // 当前蛇头能否吃到食物
            let canEatFood=(newV,oldV)=>{
                let x=snake.x
                let y=snake.y

                return map.value[x][y] === 3;

            }
            let eatFood=(newV,oldValue)=>{

                // 增加积分
                gameSetting.score++
                // 增加速度
              updateSpeed()


                console.log('当前得分:'+gameSetting.score)
                console.log('当前速度:'+gameSetting.speed)

                // 增加蛇身
                appendSnakeBody(oldValue[0],oldValue[1])
                // 修改蛇身信息
                updateSnakeBody(newV,oldValue)


                // 重新生成食物
                createFood()

                // 重新绘制地图
                updateMap()
            }


            // 修改snack.body,顺便删除蛇尾
            let updateSnakeBody=(newV,oldV)=>{
                // 更新body
                // 深拷贝
                let last={
                    ...snake.body[0]
                }
                let old
                for(let i=0;i<snake.len;i++){
                    let item=snake.body[i]

                    if( i===0){

                        // 蛇头
                        item.x=newV[0]
                        item.y=newV[1]

                    }else{

                        // 当前需要跳到的位置
                        old={
                            ...last
                        }
                        // 记录当前位置，用于下一个结点过来
                        last={
                            ...item
                        }
                        item.x=old.x
                        item.y=old.y

                    }
                }


                // 更新蛇尾
                // 如果只有一个节点
                if(snake.len>1){
                    let snakeLast=snake.body[snake.len-1]
                    snake.lastX=snakeLast.x
                    snake.lastY=snakeLast.y
                }else{
                    snake.lastX=snake.x
                    snake.lastY=snake.y
                }



            }
            let updateMap=()=>{

                for (let i=0;i<snake.len;i++) {
                    let item=snake.body[i]
                    if( i===0){
                        // 蛇头为1
                        map.value[item.x][item.y]=1
                    }else{
                        // 蛇身为2
                        map.value[item.x][item.y]=2
                    }

                }
            }
            let moveSnake=(newV,oldV)=>{

                // 删除尾巴
                map.value[snake.lastX][snake.lastY]=0


                // 更新蛇身
                updateSnakeBody(newV,oldV)

                updateMap()



            }

            // 初始化游戏
            let initGame= () => {
                initMap()
                initGameSetting()
                initSnake()
                createFood()

            }
            // 创建食物
            let createFood=()=>{

                while(true){

                    let foodX=Math.floor(Math.random()*map.mapSetting.row)
                    let foodY=Math.floor(Math.random()*map.mapSetting.col)
                    console.log('food: '+foodX+' - '+foodY)
                    if(map.value[foodX][foodY] === 0){
                        console.log('Food created successfully')
                        map.value[foodX][foodY]=3
                        break
                    }
                }

            }

            let initGameSetting=()=>{
                // 隐藏菜单
                obj.showMenu=false
                gameSetting.score=1
                gameSetting.speed=100
                gameSetting.defaultMoveDirection=2
                gameSetting.play=true

            }
            // 初始化地图 0 空地 / 1 蛇头 / 2 蛇身 / 3 食物
            let initMap=()=>{
                map.value=[]
                for(let i=0;i<map.mapSetting.row;i++){
                    let arr=[];
                    for(let j=0;j<map.mapSetting.col;j++){
                        arr[j]=0;
                    }
                    map.value.push(arr)
                }

            }

            // 初始化蛇坐标
            let initSnake=()=>{
                // 初始化蛇头坐标
                snake.x=map.mapSetting.row/2
                snake.y=map.mapSetting.col/2
                // 初始化蛇尾坐标
                snake.lastX=snake.x
                snake.lastY=snake.y
                // 初始化蛇body
                snake.body=[]
                appendSnakeBody(snake.x,snake.y)
                // appendSnakeBody(snake.x+1,snake.y)
                // 初始化长度
                snake.len=snake.body.length

                // 初始化运动方向
                snake.moveDirection=gameSetting.defaultMoveDirection
                // 添加蛇到图上
                updateMap()
            }
            // 判断地图格属性 0 空白 / 1 蛇头 / 2 蛇身 / 3食物
            let getColor=computed((i)=>(i)=>{

                switch (i) {
                    case 0:return 'space';
                    case 1:return 'snake-head';
                    case 2:return 'snake';
                    case 3:return 'food'
                }
            })
            // 计算地图width
            let getMapWidth=computed(()=>{
                let setting = map.mapSetting
                let num=Math.max(setting.col,setting.row)
                return num*setting.itemWidth+num*2+'px'
            })
            // 计算地图height
            let getMapHeight=computed(()=>{
                let setting = map.mapSetting
                let num=Math.max(setting.col,setting.row)
                return num*setting.itemWidth+num*2+'px'
            })
            let moveLeft=()=>{
                // 右移时不能左移
                if(snake.moveDirection !==3 ) {
                    snake.y--;
                    snake.moveDirection=1
                }else{
                    obj.backCount++
                    console.log('真男人不能回头')
                }

            }
            let moveUp=()=>{
                // 下移时不能上移
                if(snake.moveDirection !==4 ) {
                    snake.x--;
                    snake.moveDirection=2

                }else{
                    obj.backCount++
                    console.log('真男人不能回头')
                }
            }
            let moveRight=()=>{
                // 左移时不能右移
                if(snake.moveDirection !==1 ){
                    snake.y++;
                    snake.moveDirection=3
                }else{
                    obj.backCount++
                    console.log('真男人不能回头')
                }

            }
            let moveDown=()=>{
                // 上移时不能下移
                if(snake.moveDirection !==2 ) {
                    snake.x++;
                    snake.moveDirection=4
                }else{
                    console.log('真男人不能回头')
                    obj.backCount++
                }
            }

            let initKeyboardEvent=()=>{

                document.onkeydown=()=>{

                    if(obj.backCount === 50){
                        errorMessage("别再回头了\n往事如烟消云散,就随他去吧")
                        // alert('别再回头了\n往事如烟消云散,就随他去吧')
                        obj.backCount=0
                    }

                    let key = window.event.keyCode;

                    switch (key) {
                        // 左
                        case 65:
                        case 37:

                           moveLeft()
                           return false
                            // 上
                        case 38:
                        case 87:
                            moveUp()
                            return false
                        // 右
                        case 39:
                        case 68:
                            moveRight()
                            return false
                        // 下
                        case 40:
                        case 83:
                            moveDown()
                            return false
                        case 27:
                            // 弹出菜单
                            menuToggle()
                            return false
                        case 32:
                            pauseGame()
                            return false

                    }

                }
            }


            watch([()=>snake.x,()=>snake.y],(newV,oldV)=>{

                if(check()){
                    if(canEatFood(newV,oldV)){
                        eatFood(newV,oldV)
                    }else{
                        // 如果有发生过变化，则执行
                        // 防止初始化后出错
                        let body =snake.body
                        if( newV[0]!==body[0].x || newV[1]!==body[0].y){

                            moveSnake(newV,oldV)
                        }
                    }

                }else{
                    // 重新渲染地图，显示最后的死亡时刻
                    updateMap()
                    // 提示消息
                    alert('Game Over\n您最终的得分:'+gameSetting.score)
                   // 游戏结束，则重新初始化游戏
                   initGame()
                }

            })
            onMounted(()=>{
                initKeyboardEvent()
                initGame()
                goTo(0,80)
                startGame()

            })
            return{
                obj,
                map,
                snake,
                gameSetting,
                getColor,
                getMapWidth,
                getMapHeight,
                updateGameSetting,
                getGameLevel,
                cancelGameSetting

            }
        }
    }
</script>

<style scoped lang="less">
    .snake-box{
        width: 100%;
        height: 100%;


        .snake-game-title{

            width: 100%;
            color: white;
            position: fixed;
            top: 250px;
            right: 10px;
            display: flex;
            flex-direction: column;
            align-items: flex-end;


            span{
                color: tomato;
                font-size: 20px;
            }

            .game-manual-box{

                margin-top: 50px;
                display: flex;
                flex-direction: column;
                align-items: flex-start;
                color: #42b983;
                .game-manual{
                    color: white;
                    font-size: 16px;
                    margin: 10px;
                }

            }

        }
        .snake-map{

            display: flex;
            flex-wrap: wrap;
            flex-direction: column;
            div{

            }
            span{
                display: inline-block;
                margin: 1px;
                border: 1px solid gray;
            }
            .space{
               background-color: gray;
            }
            .food{
                background-color: #42b983;
            }
            .snake{
                background-color: tomato;
            }
            .snake-head{
                background-color: purple;
            }
        }
    }
</style>